package cn.gemiman.daoyi.module.cms.controller.app.articledetail;

import cn.gemiman.daoyi.framework.common.enums.CommonStatusEnum;
import cn.gemiman.daoyi.framework.common.pojo.CommonResult;
import cn.gemiman.daoyi.framework.common.pojo.PageParam;
import cn.gemiman.daoyi.framework.common.pojo.PageResult;
import cn.gemiman.daoyi.framework.common.util.object.BeanUtils;
import cn.gemiman.daoyi.framework.security.core.util.SecurityFrameworkUtils;
import cn.gemiman.daoyi.framework.web.core.util.WebFrameworkUtils;
import cn.gemiman.daoyi.module.cms.controller.admin.articlecategory.vo.CmsArticleCategoryRespVO;
import cn.gemiman.daoyi.module.cms.controller.admin.articledetail.vo.ArticleDetailPageReqVO;
import cn.gemiman.daoyi.module.cms.controller.admin.articledetail.vo.ArticleDetailRespVO;
import cn.gemiman.daoyi.module.cms.controller.admin.articledetailreadlogs.vo.ArticleDetailReadLogsPageReqVO;
import cn.gemiman.daoyi.module.cms.controller.admin.articledetailreadlogs.vo.ArticleDetailReadLogsSaveReqVO;
import cn.gemiman.daoyi.module.cms.controller.app.articledetail.vo.AppArticleListRespVO;
import cn.gemiman.daoyi.module.cms.controller.app.articledetail.vo.AppRecommendArticleVO;
import cn.gemiman.daoyi.module.cms.controller.app.articledetail.vo.BlogTimelineGetArticleListVO;
import cn.gemiman.daoyi.module.cms.dal.dataobject.articledetail.ArticleDetailDO;
import cn.gemiman.daoyi.module.cms.dal.mysql.articlecategory.CmsArticleCategoryMapper;
import cn.gemiman.daoyi.module.cms.service.articledetail.ArticleDetailService;
import cn.gemiman.daoyi.module.cms.service.articledetailreadlogs.ArticleDetailReadLogsService;
import cn.gemiman.daoyi.module.system.api.user.AdminUserApi;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static cn.gemiman.daoyi.framework.common.pojo.CommonResult.error;
import static cn.gemiman.daoyi.framework.common.pojo.CommonResult.success;
import static cn.gemiman.daoyi.module.cms.enums.ErrorCodeConstants.ARTICLE_DETAIL_NOT_EXISTS;

@Tag(name = "用户 APP - 文章")
@RestController
@RequestMapping("/cms/article-detail")
@Validated
public class AppArticleDetailController {

    @Resource
    private ArticleDetailService articleDetailService;
    @Resource
    private CmsArticleCategoryMapper cmsArticleCategoryMapper;
    @Resource
    private ArticleDetailReadLogsService articleDetailReadLogsService;
    @Resource
    private AdminUserApi adminUserApi;

    @GetMapping("/get")
    @Operation(summary = "获得文章")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    public CommonResult<ArticleDetailRespVO> getArticleDetail(@RequestParam("id") Long id) {
        ArticleDetailDO articleDetail = articleDetailService.getArticleDetail(id, true);
        if (articleDetail == null || CommonStatusEnum.isDisable(articleDetail.getStatus())) {
            return error(ARTICLE_DETAIL_NOT_EXISTS);
        }
        ArticleDetailRespVO bean = BeanUtils.toBean(articleDetail, ArticleDetailRespVO.class);
        try {
            ArticleDetailReadLogsPageReqVO pageReqVO = new ArticleDetailReadLogsPageReqVO().setArticleId(id);
            pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
            ExecutorService executorService = Executors.newCachedThreadPool();
            Future<CmsArticleCategoryRespVO> categoryRespVOFuture = executorService.submit(() -> BeanUtils.toBean(cmsArticleCategoryMapper.selectById(bean.getCategoryId()), CmsArticleCategoryRespVO.class));
            Future<Long> readingDurationFuture = executorService.submit(() -> articleDetailReadLogsService.getArticleDetailReadLogsPage(pageReqVO).getList()
                    .stream().filter(rl -> null != rl.getBeginTime() && rl.getEndTime() != null)
                    .mapToLong(rl -> LocalDateTimeUtil.between(rl.getBeginTime(), rl.getEndTime()).get(ChronoUnit.SECONDS) * 1000)
                    .sum());
            Future<String> authorNameFuture = executorService.submit(() -> {
                if (null == articleDetail.getCreator()) {
                    return null;
                }
                return adminUserApi.getUser(Long.valueOf(articleDetail.getCreator())).getCheckedData().getNickname();
            });
            bean.setCategory(categoryRespVOFuture.get());
            bean.setReadingDuration(readingDurationFuture.get());
            bean.setAuthorName(authorNameFuture.get());
            executorService.shutdown();
        } catch (Exception ignored) {
        }
        return success(bean);
    }


    @PostMapping("/addReadingDuration")
    @Operation(summary = "登记阅读时长")
    public CommonResult<Long> addReadingDuration(@Valid @RequestBody ArticleDetailReadLogsSaveReqVO createReqVO) {
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        createReqVO.setUserId(loginUserId);
        return success(articleDetailReadLogsService.createArticleDetailReadLogs(createReqVO));
    }


    @GetMapping("/getRecommendArticleById/{id}")
    @Operation(summary = "获取推荐文章")
    public CommonResult<AppRecommendArticleVO> getRecommendArticleById(@PathVariable("id") Long id) {
        ArticleDetailRespVO checkedData = this.getArticleDetail(id).getCheckedData();
        ArticleDetailPageReqVO pageReqVO = new ArticleDetailPageReqVO();
        pageReqVO.setCategoryId(checkedData.getCategoryId());
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<AppArticleListRespVO> list = this.getArticleDetailPage(pageReqVO).getCheckedData().getList();
        if (CollUtil.size(list) < 2) {
            return success(new AppRecommendArticleVO());
        }
        int curr = IntStream.range(0, list.size()).filter(i -> id.equals(list.get(i).getId())).findFirst().orElse(0);
        AppRecommendArticleVO result = new AppRecommendArticleVO();
        result.setNext(curr + 1 < list.size() ? list.get(curr + 1) : list.getFirst());
        result.setPrevious(curr - 1 >= 0 ? list.get(curr - 1) : list.getLast());
        list.remove(curr);
        Collections.shuffle(list);
        result.setRecommend(CollUtil.sub(list, 0, 5));
        return success(result);
    }


    @GetMapping("/blogTimelineGetArticleList")
    @Operation(summary = "获得文章时间线分页")
    public CommonResult<PageResult<BlogTimelineGetArticleListVO>> getBlogTimelineGetArticleList(@Valid ArticleDetailPageReqVO pageReqVO) {
        PageResult<AppArticleListRespVO> articleDetailPage = this.getArticleDetailPage(pageReqVO).getCheckedData();
        PageResult<BlogTimelineGetArticleListVO> result = new PageResult<>();
        BeanUtil.copyProperties(articleDetailPage, result, "list");
        List<AppArticleListRespVO> list = articleDetailPage.getList();
        Map<Integer, List<AppArticleListRespVO>> collect = list.stream().collect(Collectors.groupingBy(v -> v.getCreateTime().getYear()));
        List<BlogTimelineGetArticleListVO> resList = CollUtil.toList();
        collect.forEach((k, v) -> {
            resList.add(new BlogTimelineGetArticleListVO().setYear(k.toString()).setArticleList(v));
        });
        resList.sort(Comparator.comparing(BlogTimelineGetArticleListVO::getYear).reversed());
        return success(result.setList(resList));
    }

    @GetMapping("/page")
    @Operation(summary = "获得文章分页")
    public CommonResult<PageResult<AppArticleListRespVO>> getArticleDetailPage(@Valid ArticleDetailPageReqVO pageReqVO) {
        pageReqVO.setAppId(WebFrameworkUtils.getAppId());
        pageReqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
        PageResult<ArticleDetailDO> pageResult = articleDetailService.getArticleDetailPage(pageReqVO);
        PageResult<AppArticleListRespVO> result = BeanUtils.toBean(pageResult, AppArticleListRespVO.class);
        List<AppArticleListRespVO> list = result.getList();
        if (CollUtil.isNotEmpty(list)) {
            cmsArticleCategoryMapper.selectBatchIds(list.stream().map(AppArticleListRespVO::getCategoryId).toList())
                    .parallelStream()
                    .forEach(category -> list.forEach(article -> {
                        if (article.getCategoryId().equals(category.getId())) {
                            article.setCategory(BeanUtils.toBean(category, CmsArticleCategoryRespVO.class));
                        }
                    }));
        }
        return success(result);
    }
}
